package com.szh.library.book.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.szh.common.enums.BookTypeEnum;
import com.szh.common.enums.ResultCodeEnum;
import com.szh.common.exception.ServiceLibraryException;
import com.szh.common.result.Result;
import com.szh.library.book.client.UserFeignClient;
import com.szh.library.book.mapper.BookMapper;
import com.szh.library.book.service.BookService;
import com.szh.model.Book;
import com.szh.model.User;
import com.szh.vo.BookFindVo;
import com.szh.vo.BookSaveVo;
import com.szh.vo.BookUpdateVo;
import com.szh.vo.UserSelectVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author: SongZiHao
 * @date: 2023/5/10
 */
@Service
public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements BookService {

    private static final Logger LOGGER = LoggerFactory.getLogger(BookServiceImpl.class);

    private static final Map<Integer, BookTypeEnum> BOOK_TYPE_ENUM_MAP = new HashMap<>();

    @Autowired
    private UserFeignClient userFeignClient;

    static {
        BOOK_TYPE_ENUM_MAP.put(1, BookTypeEnum.儿童类);
        BOOK_TYPE_ENUM_MAP.put(2, BookTypeEnum.专业类);
        BOOK_TYPE_ENUM_MAP.put(3, BookTypeEnum.历史类);
        BOOK_TYPE_ENUM_MAP.put(4, BookTypeEnum.修养类);
    }

    /**
     * 根据id查询图书
     * @param id 图书id
     * @return Book
     */
    @Override
    public Book findBookById(Long id) {
        LOGGER.info("findBookById start....");
        LOGGER.info("待查询图书id ===> {}", id);
        Book book = this.getById(id);
        if (null == book) {
            LOGGER.error("根据此 id ===> {} 查询的图书信息为空....", id);
            throw new ServiceLibraryException(ResultCodeEnum.QUERY_ONE_NOT_FOUND.getCode(),
                    ResultCodeEnum.QUERY_ONE_NOT_FOUND.getMessage());
        }
        LOGGER.info("根据此 id ===> {} 查询的图书信息 ===> {}", id, JSON.toJSONString(book));
        return book;
    }

    /**
     * 查询所有图书
     * @return List<Book>
     */
    @Override
    public List<Book> findAllBooks() {
        LOGGER.info("findAllBooks start....");
        List<Book> bookList = this.list();
        LOGGER.info("查询到的图书列表 ===> {}", JSON.toJSONString(bookList));
        return bookList;
    }

    /**
     * 条件查询图书，带分页
     * @param page 页码
     * @param limit 每页记录数
     * @param bookFindVo 查询条件vo类
     * @return Page<Book>
     */
    @Override
    public Page<Book> findBooksByConditionPage(Long page, Long limit, BookFindVo bookFindVo) {
        LOGGER.info("findBooksByConditionPage start....");
        LOGGER.info("findBooksByConditionPage接口入参 ===> page页码：{}", page);
        LOGGER.info("findBooksByConditionPage接口入参 ===> limit每页记录数：{}", limit);
        LOGGER.info("findBooksByConditionPage接口入参 ===> 查询条件：{}", bookFindVo);
        Page<Book> pageParam = new Page<>(page, limit);
        LambdaQueryWrapper<Book> queryWrapper = new LambdaQueryWrapper<>();
        String name = bookFindVo.getName();
        Integer type = bookFindVo.getType();
        Date createTimeBegin = bookFindVo.getCreateTimeBegin();
        Date createTimeEnd = bookFindVo.getCreateTimeEnd();
        if (!StringUtils.isEmpty(name)) {
            queryWrapper.like(Book::getName, name);
        }
        if (!StringUtils.isEmpty(type)) {
            queryWrapper.eq(Book::getType, type);
        }
        if (!StringUtils.isEmpty(createTimeBegin)) {
            queryWrapper.ge(Book::getCreateTime, createTimeBegin);
        }
        if (!StringUtils.isEmpty(createTimeEnd)) {
            queryWrapper.le(Book::getCreateTime, createTimeEnd);
        }
        Page<Book> pageModel = this.page(pageParam, queryWrapper);
        List<Book> books = pageModel.getRecords();
        if (CollectionUtils.isEmpty(books)) {
            LOGGER.error("根据此条件查询的图书列表为空 ===> {}", JSON.toJSONString(bookFindVo));
            return new Page<>();
        }
        LOGGER.info("根据此条件查询的图书总数 ===> {}", pageModel.getTotal());
        LOGGER.info("根据此条件查询的图书列表 ===> {}", JSON.toJSONString(books));
        return pageModel;
    }

    /**
     * 保存图书
     * @param bookSaveVo 图书保存vo类
     * @return 是否保存成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
    public boolean saveBook(BookSaveVo bookSaveVo) {
        LOGGER.info("saveBook start....");
        LOGGER.info("新增图书的部分信息 ===> {}", JSON.toJSONString(bookSaveVo));
        String name = bookSaveVo.getName();
        String intro = bookSaveVo.getIntro();
        Integer type = bookSaveVo.getType();
        BigDecimal price = bookSaveVo.getPrice();
        String author = bookSaveVo.getAuthor();
        if (StringUtils.isEmpty(name) || StringUtils.isEmpty(intro) || type <= 0 ||
            price.compareTo(new BigDecimal("0.00")) <= 0 || StringUtils.isEmpty(author)) {
            LOGGER.error("新增图书的信息中存在非法数据 ===> {}", JSON.toJSONString(bookSaveVo));
            throw new ServiceLibraryException(ResultCodeEnum.ILLEGAL_PARAM.getCode(),
                    ResultCodeEnum.ILLEGAL_PARAM.getMessage());
        }
        Book book = Book.builder()
                .name(name)
                .intro(intro)
                .type(getBookType(type))
                .price(price)
                .author(author)
                .build();
        book.setCreateTime(new Date());
        LOGGER.info("待新增图书的信息 ===> {}", JSON.toJSONString(book));
        boolean flag = this.save(book);
        if (flag) {
            LOGGER.info("新增成功 ===> {}", JSON.toJSONString(book));
            return true;
        } else {
            LOGGER.error("新增异常....");
            return false;
        }
    }

    /**
     * 根据id修改图书
     * @param bookUpdateVo 图书修改vo类
     * @return 是否修改成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
    public boolean updateBook(BookUpdateVo bookUpdateVo) {
        LOGGER.info("updateBook start....");
        LOGGER.info("待修改图书的部分信息 ===> {}", JSON.toJSONString(bookUpdateVo));
        this.findBookById(bookUpdateVo.getId()); //修改之前先查一下有没有这条记录，没有了话直接抛异常返回
        Book book = new Book();
        BeanUtils.copyProperties(bookUpdateVo, book);
        if (StringUtils.isEmpty(book.getName()) || StringUtils.isEmpty(book.getIntro()) || book.getType() <= 0 ||
            book.getPrice().compareTo(new BigDecimal("0.00")) <= 0 || StringUtils.isEmpty(book.getAuthor())) {
            LOGGER.error("修改之后的图书部分信息不合法，请更正一下再次提交 ===> {}", JSON.toJSONString(book));
            throw new ServiceLibraryException(ResultCodeEnum.ILLEGAL_PARAM.getCode(),
                    ResultCodeEnum.ILLEGAL_PARAM.getMessage());
        }
        book.setUpdateTime(new Date());
        boolean flag = this.updateById(book);
        if (flag) {
            LOGGER.info("修改成功!!!");
            return true;
        } else {
            LOGGER.error("修改异常....");
            throw new ServiceLibraryException(ResultCodeEnum.UPDATE_FAILED.getCode(),
                    ResultCodeEnum.UPDATE_FAILED.getMessage());
        }
    }

    /**
     * 根据id删除图书
     * @param id 图书id
     * @return 是否删除成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
    public boolean deleteBookById(Long id) {
        LOGGER.info("deleteBookById start....");
        LOGGER.info("待删除图书id ===> {}", id);
        Book book = this.findBookById(id); //删除之前先查一下有没有这条记录，没有了话直接抛异常返回
        boolean flag = this.removeById(id);
        if (flag) {
            LOGGER.info("根据此 id ===> {} 删除图书成功，所删图书信息 ===> {}", id, JSON.toJSONString(book));
            return true;
        } else {
            LOGGER.error("根据此 id ===> {} 删除图书失败", id);
            throw new ServiceLibraryException(ResultCodeEnum.DELETE_FAILED.getCode(),
                    ResultCodeEnum.DELETE_FAILED.getMessage());
        }
    }

    /**
     * 批量删除图书
     * @param bookIds 待删图书id集合
     * @return 是否批量删除成功
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
    public boolean deleteBatchByIds(List<Long> bookIds) {
        LOGGER.info("deleteBatchByIds start....");
        LOGGER.info("待删图书id集合 ===> {}", JSON.toJSONString(bookIds));
        int row = baseMapper.deleteBatchIds(bookIds);
        if (row == bookIds.size()) {
            LOGGER.info("批量删除成功!!!");
            return true;
        } else {
            LOGGER.error("批量删除异常....");
            throw new ServiceLibraryException(ResultCodeEnum.DELETE_FAILED.getCode(),
                    ResultCodeEnum.DELETE_FAILED.getMessage());
        }
    }

    /**
     * 远程接口调用：根据id查询用户
     * @param id 用户id
     * @return User
     */
    @Override
    public User openFeignSelectUserById(Long id) {
        LOGGER.info("openFeignSelectUserById start....");
        LOGGER.info("待查询用户id ===> {}", id);
        Result<User> result = userFeignClient.selectUserById(id);
        User user = result.getData();
        if (null == user) {
            LOGGER.error("根据此 id ===> {} 远程查询的用户信息为空....", id);
            throw new ServiceLibraryException(ResultCodeEnum.QUERY_ONE_NOT_FOUND.getCode(),
                    ResultCodeEnum.QUERY_ONE_NOT_FOUND.getMessage());
        }
        LOGGER.info("根据此 id ===> {} 远程查询的用户信息 ===> {}", id, JSON.toJSONString(user));
        return user;
    }

    /**
     * 远程接口调用：查询所有用户
     * @return List<User> 用户列表
     */
    @Override
    public List<User> openFeignSelectAllUsers() {
        LOGGER.info("openFeignSelectAllUsers start....");
        Result<List<User>> result = userFeignClient.selectAllUsers();
        List<User> userList = result.getData();
        LOGGER.info("远程查询到的用户列表 ===> {}", JSON.toJSONString(userList));
        return userList;
    }

    /**
     * 远程接口调用：条件查询用户，带分页
     * @param page 页码
     * @param limit 每页记录数
     * @param userSelectVo 查询条件
     * @return Page<User>
     */
    @Override
    public Page<User> openFeignSelectUsersByConditionPage(Long page, Long limit, UserSelectVo userSelectVo) {
        LOGGER.info("openFeignSelectUsersByConditionPage start....");
        Result<Page<User>> result = userFeignClient.selectUsersByConditionPage(page, limit, userSelectVo);
        Page<User> pageModel = result.getData();
        List<User> users = pageModel.getRecords();
        if (CollectionUtils.isEmpty(users)) {
            LOGGER.error("根据此条件查询的用户列表为空 ===> {}", JSON.toJSONString(userSelectVo));
            return new Page<>(page, limit);
        }
        LOGGER.info("根据此条件远程查询的用户总数 ===> {}", pageModel.getTotal());
        LOGGER.info("根据此条件远程查询的用户列表 ===> {}", JSON.toJSONString(users));
        return pageModel;
    }

    private Integer getBookType(Integer bookType) {
        return BOOK_TYPE_ENUM_MAP.get(bookType).getBookTypeId();
    }
}
